agora inbox for [email protected]help / color / mirror / Atom feed
[PATCH v13 7/8] Row pattern recognition patch (tests). 813+ messages / 2 participants [nested] [flat]
* [PATCH v13 7/8] Row pattern recognition patch (tests). @ 2024-01-22 09:45 Tatsuo Ishii <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Tatsuo Ishii @ 2024-01-22 09:45 UTC (permalink / raw) --- src/test/regress/expected/rpr.out | 821 +++++++++++++++++++++++++++++ src/test/regress/parallel_schedule | 2 +- src/test/regress/sql/rpr.sql | 392 ++++++++++++++ 3 files changed, 1214 insertions(+), 1 deletion(-) create mode 100644 src/test/regress/expected/rpr.out create mode 100644 src/test/regress/sql/rpr.sql diff --git a/src/test/regress/expected/rpr.out b/src/test/regress/expected/rpr.out new file mode 100644 index 0000000000..e8998ebf45 --- /dev/null +++ b/src/test/regress/expected/rpr.out @@ -0,0 +1,821 @@ +-- +-- Test for row pattern definition clause +-- +CREATE TEMP TABLE stock ( + company TEXT, + tdate DATE, + price INTEGER +); +INSERT INTO stock VALUES ('company1', '2023-07-01', 100); +INSERT INTO stock VALUES ('company1', '2023-07-02', 200); +INSERT INTO stock VALUES ('company1', '2023-07-03', 150); +INSERT INTO stock VALUES ('company1', '2023-07-04', 140); +INSERT INTO stock VALUES ('company1', '2023-07-05', 150); +INSERT INTO stock VALUES ('company1', '2023-07-06', 90); +INSERT INTO stock VALUES ('company1', '2023-07-07', 110); +INSERT INTO stock VALUES ('company1', '2023-07-08', 130); +INSERT INTO stock VALUES ('company1', '2023-07-09', 120); +INSERT INTO stock VALUES ('company1', '2023-07-10', 130); +INSERT INTO stock VALUES ('company2', '2023-07-01', 50); +INSERT INTO stock VALUES ('company2', '2023-07-02', 2000); +INSERT INTO stock VALUES ('company2', '2023-07-03', 1500); +INSERT INTO stock VALUES ('company2', '2023-07-04', 1400); +INSERT INTO stock VALUES ('company2', '2023-07-05', 1500); +INSERT INTO stock VALUES ('company2', '2023-07-06', 60); +INSERT INTO stock VALUES ('company2', '2023-07-07', 1100); +INSERT INTO stock VALUES ('company2', '2023-07-08', 1300); +INSERT INTO stock VALUES ('company2', '2023-07-09', 1200); +INSERT INTO stock VALUES ('company2', '2023-07-10', 1300); +SELECT * FROM stock; + company | tdate | price +----------+------------+------- + company1 | 07-01-2023 | 100 + company1 | 07-02-2023 | 200 + company1 | 07-03-2023 | 150 + company1 | 07-04-2023 | 140 + company1 | 07-05-2023 | 150 + company1 | 07-06-2023 | 90 + company1 | 07-07-2023 | 110 + company1 | 07-08-2023 | 130 + company1 | 07-09-2023 | 120 + company1 | 07-10-2023 | 130 + company2 | 07-01-2023 | 50 + company2 | 07-02-2023 | 2000 + company2 | 07-03-2023 | 1500 + company2 | 07-04-2023 | 1400 + company2 | 07-05-2023 | 1500 + company2 | 07-06-2023 | 60 + company2 | 07-07-2023 | 1100 + company2 | 07-08-2023 | 1300 + company2 | 07-09-2023 | 1200 + company2 | 07-10-2023 | 1300 +(20 rows) + +-- basic test using PREV +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w, + nth_value(tdate, 2) OVER w AS nth_second + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP+ DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + company | tdate | price | first_value | last_value | nth_second +----------+------------+-------+-------------+------------+------------ + company1 | 07-01-2023 | 100 | 100 | 140 | 07-02-2023 + company1 | 07-02-2023 | 200 | | | + company1 | 07-03-2023 | 150 | | | + company1 | 07-04-2023 | 140 | | | + company1 | 07-05-2023 | 150 | | | + company1 | 07-06-2023 | 90 | 90 | 120 | 07-07-2023 + company1 | 07-07-2023 | 110 | | | + company1 | 07-08-2023 | 130 | | | + company1 | 07-09-2023 | 120 | | | + company1 | 07-10-2023 | 130 | | | + company2 | 07-01-2023 | 50 | 50 | 1400 | 07-02-2023 + company2 | 07-02-2023 | 2000 | | | + company2 | 07-03-2023 | 1500 | | | + company2 | 07-04-2023 | 1400 | | | + company2 | 07-05-2023 | 1500 | | | + company2 | 07-06-2023 | 60 | 60 | 1200 | 07-07-2023 + company2 | 07-07-2023 | 1100 | | | + company2 | 07-08-2023 | 1300 | | | + company2 | 07-09-2023 | 1200 | | | + company2 | 07-10-2023 | 1300 | | | +(20 rows) + +-- basic test using PREV. UP appears twice +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w, + nth_value(tdate, 2) OVER w AS nth_second + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP+ DOWN+ UP+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + company | tdate | price | first_value | last_value | nth_second +----------+------------+-------+-------------+------------+------------ + company1 | 07-01-2023 | 100 | 100 | 150 | 07-02-2023 + company1 | 07-02-2023 | 200 | | | + company1 | 07-03-2023 | 150 | | | + company1 | 07-04-2023 | 140 | | | + company1 | 07-05-2023 | 150 | | | + company1 | 07-06-2023 | 90 | 90 | 130 | 07-07-2023 + company1 | 07-07-2023 | 110 | | | + company1 | 07-08-2023 | 130 | | | + company1 | 07-09-2023 | 120 | | | + company1 | 07-10-2023 | 130 | | | + company2 | 07-01-2023 | 50 | 50 | 1500 | 07-02-2023 + company2 | 07-02-2023 | 2000 | | | + company2 | 07-03-2023 | 1500 | | | + company2 | 07-04-2023 | 1400 | | | + company2 | 07-05-2023 | 1500 | | | + company2 | 07-06-2023 | 60 | 60 | 1300 | 07-07-2023 + company2 | 07-07-2023 | 1100 | | | + company2 | 07-08-2023 | 1300 | | | + company2 | 07-09-2023 | 1200 | | | + company2 | 07-10-2023 | 1300 | | | +(20 rows) + +-- basic test using PREV. Use '*' +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w, + nth_value(tdate, 2) OVER w AS nth_second + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP* DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + company | tdate | price | first_value | last_value | nth_second +----------+------------+-------+-------------+------------+------------ + company1 | 07-01-2023 | 100 | 100 | 140 | 07-02-2023 + company1 | 07-02-2023 | 200 | | | + company1 | 07-03-2023 | 150 | | | + company1 | 07-04-2023 | 140 | | | + company1 | 07-05-2023 | 150 | 150 | 90 | 07-06-2023 + company1 | 07-06-2023 | 90 | | | + company1 | 07-07-2023 | 110 | 110 | 120 | 07-08-2023 + company1 | 07-08-2023 | 130 | | | + company1 | 07-09-2023 | 120 | | | + company1 | 07-10-2023 | 130 | | | + company2 | 07-01-2023 | 50 | 50 | 1400 | 07-02-2023 + company2 | 07-02-2023 | 2000 | | | + company2 | 07-03-2023 | 1500 | | | + company2 | 07-04-2023 | 1400 | | | + company2 | 07-05-2023 | 1500 | 1500 | 60 | 07-06-2023 + company2 | 07-06-2023 | 60 | | | + company2 | 07-07-2023 | 1100 | 1100 | 1200 | 07-08-2023 + company2 | 07-08-2023 | 1300 | | | + company2 | 07-09-2023 | 1200 | | | + company2 | 07-10-2023 | 1300 | | | +(20 rows) + +-- basic test with none greedy pattern +SELECT company, tdate, price, count(*) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (A A A) + DEFINE + A AS price >= 140 AND price <= 150 +); + company | tdate | price | count +----------+------------+-------+------- + company1 | 07-01-2023 | 100 | 0 + company1 | 07-02-2023 | 200 | 0 + company1 | 07-03-2023 | 150 | 3 + company1 | 07-04-2023 | 140 | + company1 | 07-05-2023 | 150 | + company1 | 07-06-2023 | 90 | 0 + company1 | 07-07-2023 | 110 | 0 + company1 | 07-08-2023 | 130 | 0 + company1 | 07-09-2023 | 120 | 0 + company1 | 07-10-2023 | 130 | 0 + company2 | 07-01-2023 | 50 | 0 + company2 | 07-02-2023 | 2000 | 0 + company2 | 07-03-2023 | 1500 | 0 + company2 | 07-04-2023 | 1400 | 0 + company2 | 07-05-2023 | 1500 | 0 + company2 | 07-06-2023 | 60 | 0 + company2 | 07-07-2023 | 1100 | 0 + company2 | 07-08-2023 | 1300 | 0 + company2 | 07-09-2023 | 1200 | 0 + company2 | 07-10-2023 | 1300 | 0 +(20 rows) + +-- last_value() should remain consistent +SELECT company, tdate, price, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP+ DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + company | tdate | price | last_value +----------+------------+-------+------------ + company1 | 07-01-2023 | 100 | 140 + company1 | 07-02-2023 | 200 | + company1 | 07-03-2023 | 150 | + company1 | 07-04-2023 | 140 | + company1 | 07-05-2023 | 150 | + company1 | 07-06-2023 | 90 | 120 + company1 | 07-07-2023 | 110 | + company1 | 07-08-2023 | 130 | + company1 | 07-09-2023 | 120 | + company1 | 07-10-2023 | 130 | + company2 | 07-01-2023 | 50 | 1400 + company2 | 07-02-2023 | 2000 | + company2 | 07-03-2023 | 1500 | + company2 | 07-04-2023 | 1400 | + company2 | 07-05-2023 | 1500 | + company2 | 07-06-2023 | 60 | 1200 + company2 | 07-07-2023 | 1100 | + company2 | 07-08-2023 | 1300 | + company2 | 07-09-2023 | 1200 | + company2 | 07-10-2023 | 1300 | +(20 rows) + +-- omit "START" in DEFINE but it is ok because "START AS TRUE" is +-- implicitly defined. per spec. +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w, + nth_value(tdate, 2) OVER w AS nth_second + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP+ DOWN+) + DEFINE + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + company | tdate | price | first_value | last_value | nth_second +----------+------------+-------+-------------+------------+------------ + company1 | 07-01-2023 | 100 | 100 | 140 | 07-02-2023 + company1 | 07-02-2023 | 200 | | | + company1 | 07-03-2023 | 150 | | | + company1 | 07-04-2023 | 140 | | | + company1 | 07-05-2023 | 150 | | | + company1 | 07-06-2023 | 90 | 90 | 120 | 07-07-2023 + company1 | 07-07-2023 | 110 | | | + company1 | 07-08-2023 | 130 | | | + company1 | 07-09-2023 | 120 | | | + company1 | 07-10-2023 | 130 | | | + company2 | 07-01-2023 | 50 | 50 | 1400 | 07-02-2023 + company2 | 07-02-2023 | 2000 | | | + company2 | 07-03-2023 | 1500 | | | + company2 | 07-04-2023 | 1400 | | | + company2 | 07-05-2023 | 1500 | | | + company2 | 07-06-2023 | 60 | 60 | 1200 | 07-07-2023 + company2 | 07-07-2023 | 1100 | | | + company2 | 07-08-2023 | 1300 | | | + company2 | 07-09-2023 | 1200 | | | + company2 | 07-10-2023 | 1300 | | | +(20 rows) + +-- the first row start with less than or equal to 100 +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (LOWPRICE UP+ DOWN+) + DEFINE + LOWPRICE AS price <= 100, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + company | tdate | price | first_value | last_value +----------+------------+-------+-------------+------------ + company1 | 07-01-2023 | 100 | 100 | 140 + company1 | 07-02-2023 | 200 | | + company1 | 07-03-2023 | 150 | | + company1 | 07-04-2023 | 140 | | + company1 | 07-05-2023 | 150 | | + company1 | 07-06-2023 | 90 | 90 | 120 + company1 | 07-07-2023 | 110 | | + company1 | 07-08-2023 | 130 | | + company1 | 07-09-2023 | 120 | | + company1 | 07-10-2023 | 130 | | + company2 | 07-01-2023 | 50 | 50 | 1400 + company2 | 07-02-2023 | 2000 | | + company2 | 07-03-2023 | 1500 | | + company2 | 07-04-2023 | 1400 | | + company2 | 07-05-2023 | 1500 | | + company2 | 07-06-2023 | 60 | 60 | 1200 + company2 | 07-07-2023 | 1100 | | + company2 | 07-08-2023 | 1300 | | + company2 | 07-09-2023 | 1200 | | + company2 | 07-10-2023 | 1300 | | +(20 rows) + +-- second row raises 120% +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (LOWPRICE UP+ DOWN+) + DEFINE + LOWPRICE AS price <= 100, + UP AS price > PREV(price) * 1.2, + DOWN AS price < PREV(price) +); + company | tdate | price | first_value | last_value +----------+------------+-------+-------------+------------ + company1 | 07-01-2023 | 100 | 100 | 140 + company1 | 07-02-2023 | 200 | | + company1 | 07-03-2023 | 150 | | + company1 | 07-04-2023 | 140 | | + company1 | 07-05-2023 | 150 | | + company1 | 07-06-2023 | 90 | | + company1 | 07-07-2023 | 110 | | + company1 | 07-08-2023 | 130 | | + company1 | 07-09-2023 | 120 | | + company1 | 07-10-2023 | 130 | | + company2 | 07-01-2023 | 50 | 50 | 1400 + company2 | 07-02-2023 | 2000 | | + company2 | 07-03-2023 | 1500 | | + company2 | 07-04-2023 | 1400 | | + company2 | 07-05-2023 | 1500 | | + company2 | 07-06-2023 | 60 | | + company2 | 07-07-2023 | 1100 | | + company2 | 07-08-2023 | 1300 | | + company2 | 07-09-2023 | 1200 | | + company2 | 07-10-2023 | 1300 | | +(20 rows) + +-- using NEXT +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UPDOWN) + DEFINE + START AS TRUE, + UPDOWN AS price > PREV(price) AND price > NEXT(price) +); + company | tdate | price | first_value | last_value +----------+------------+-------+-------------+------------ + company1 | 07-01-2023 | 100 | 100 | 200 + company1 | 07-02-2023 | 200 | | + company1 | 07-03-2023 | 150 | | + company1 | 07-04-2023 | 140 | 140 | 150 + company1 | 07-05-2023 | 150 | | + company1 | 07-06-2023 | 90 | | + company1 | 07-07-2023 | 110 | 110 | 130 + company1 | 07-08-2023 | 130 | | + company1 | 07-09-2023 | 120 | | + company1 | 07-10-2023 | 130 | | + company2 | 07-01-2023 | 50 | 50 | 2000 + company2 | 07-02-2023 | 2000 | | + company2 | 07-03-2023 | 1500 | | + company2 | 07-04-2023 | 1400 | 1400 | 1500 + company2 | 07-05-2023 | 1500 | | + company2 | 07-06-2023 | 60 | | + company2 | 07-07-2023 | 1100 | 1100 | 1300 + company2 | 07-08-2023 | 1300 | | + company2 | 07-09-2023 | 1200 | | + company2 | 07-10-2023 | 1300 | | +(20 rows) + +-- using AFTER MATCH SKIP TO NEXT ROW +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + AFTER MATCH SKIP TO NEXT ROW + INITIAL + PATTERN (START UPDOWN) + DEFINE + START AS TRUE, + UPDOWN AS price > PREV(price) AND price > NEXT(price) +); + company | tdate | price | first_value | last_value +----------+------------+-------+-------------+------------ + company1 | 07-01-2023 | 100 | 100 | 200 + company1 | 07-02-2023 | 200 | | + company1 | 07-03-2023 | 150 | | + company1 | 07-04-2023 | 140 | 140 | 150 + company1 | 07-05-2023 | 150 | | + company1 | 07-06-2023 | 90 | | + company1 | 07-07-2023 | 110 | 110 | 130 + company1 | 07-08-2023 | 130 | | + company1 | 07-09-2023 | 120 | | + company1 | 07-10-2023 | 130 | | + company2 | 07-01-2023 | 50 | 50 | 2000 + company2 | 07-02-2023 | 2000 | | + company2 | 07-03-2023 | 1500 | | + company2 | 07-04-2023 | 1400 | 1400 | 1500 + company2 | 07-05-2023 | 1500 | | + company2 | 07-06-2023 | 60 | | + company2 | 07-07-2023 | 1100 | 1100 | 1300 + company2 | 07-08-2023 | 1300 | | + company2 | 07-09-2023 | 1200 | | + company2 | 07-10-2023 | 1300 | | +(20 rows) + +-- match everything +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + AFTER MATCH SKIP PAST LAST ROW + INITIAL + PATTERN (A+) + DEFINE + A AS TRUE +); + company | tdate | price | first_value | last_value +----------+------------+-------+-------------+------------ + company1 | 07-01-2023 | 100 | 100 | 130 + company1 | 07-02-2023 | 200 | | + company1 | 07-03-2023 | 150 | | + company1 | 07-04-2023 | 140 | | + company1 | 07-05-2023 | 150 | | + company1 | 07-06-2023 | 90 | | + company1 | 07-07-2023 | 110 | | + company1 | 07-08-2023 | 130 | | + company1 | 07-09-2023 | 120 | | + company1 | 07-10-2023 | 130 | | + company2 | 07-01-2023 | 50 | 50 | 1300 + company2 | 07-02-2023 | 2000 | | + company2 | 07-03-2023 | 1500 | | + company2 | 07-04-2023 | 1400 | | + company2 | 07-05-2023 | 1500 | | + company2 | 07-06-2023 | 60 | | + company2 | 07-07-2023 | 1100 | | + company2 | 07-08-2023 | 1300 | | + company2 | 07-09-2023 | 1200 | | + company2 | 07-10-2023 | 1300 | | +(20 rows) + +-- backtracking with reclassification of rows +-- using AFTER MATCH SKIP PAST LAST ROW +SELECT company, tdate, price, first_value(tdate) OVER w, last_value(tdate) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + AFTER MATCH SKIP PAST LAST ROW + INITIAL + PATTERN (A+ B+) + DEFINE + A AS price > 100, + B AS price > 100 +); + company | tdate | price | first_value | last_value +----------+------------+-------+-------------+------------ + company1 | 07-01-2023 | 100 | | + company1 | 07-02-2023 | 200 | 07-02-2023 | 07-05-2023 + company1 | 07-03-2023 | 150 | | + company1 | 07-04-2023 | 140 | | + company1 | 07-05-2023 | 150 | | + company1 | 07-06-2023 | 90 | | + company1 | 07-07-2023 | 110 | 07-07-2023 | 07-10-2023 + company1 | 07-08-2023 | 130 | | + company1 | 07-09-2023 | 120 | | + company1 | 07-10-2023 | 130 | | + company2 | 07-01-2023 | 50 | | + company2 | 07-02-2023 | 2000 | 07-02-2023 | 07-05-2023 + company2 | 07-03-2023 | 1500 | | + company2 | 07-04-2023 | 1400 | | + company2 | 07-05-2023 | 1500 | | + company2 | 07-06-2023 | 60 | | + company2 | 07-07-2023 | 1100 | 07-07-2023 | 07-10-2023 + company2 | 07-08-2023 | 1300 | | + company2 | 07-09-2023 | 1200 | | + company2 | 07-10-2023 | 1300 | | +(20 rows) + +-- backtracking with reclassification of rows +-- using AFTER MATCH SKIP TO NEXT ROW +SELECT company, tdate, price, first_value(tdate) OVER w, last_value(tdate) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + AFTER MATCH SKIP TO NEXT ROW + INITIAL + PATTERN (A+ B+) + DEFINE + A AS price > 100, + B AS price > 100 +); + company | tdate | price | first_value | last_value +----------+------------+-------+-------------+------------ + company1 | 07-01-2023 | 100 | | + company1 | 07-02-2023 | 200 | 07-02-2023 | 07-05-2023 + company1 | 07-03-2023 | 150 | 07-03-2023 | 07-05-2023 + company1 | 07-04-2023 | 140 | 07-04-2023 | 07-05-2023 + company1 | 07-05-2023 | 150 | | + company1 | 07-06-2023 | 90 | | + company1 | 07-07-2023 | 110 | 07-07-2023 | 07-10-2023 + company1 | 07-08-2023 | 130 | 07-08-2023 | 07-10-2023 + company1 | 07-09-2023 | 120 | 07-09-2023 | 07-10-2023 + company1 | 07-10-2023 | 130 | | + company2 | 07-01-2023 | 50 | | + company2 | 07-02-2023 | 2000 | 07-02-2023 | 07-05-2023 + company2 | 07-03-2023 | 1500 | 07-03-2023 | 07-05-2023 + company2 | 07-04-2023 | 1400 | 07-04-2023 | 07-05-2023 + company2 | 07-05-2023 | 1500 | | + company2 | 07-06-2023 | 60 | | + company2 | 07-07-2023 | 1100 | 07-07-2023 | 07-10-2023 + company2 | 07-08-2023 | 1300 | 07-08-2023 | 07-10-2023 + company2 | 07-09-2023 | 1200 | 07-09-2023 | 07-10-2023 + company2 | 07-10-2023 | 1300 | | +(20 rows) + +-- ROWS BETWEEN CURRENT ROW AND offset FOLLOWING +SELECT company, tdate, price, first_value(tdate) OVER w, last_value(tdate) OVER w, + count(*) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING + AFTER MATCH SKIP PAST LAST ROW + PATTERN (START UP+ DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + company | tdate | price | first_value | last_value | count +----------+------------+-------+-------------+------------+------- + company1 | 07-01-2023 | 100 | 07-01-2023 | 07-03-2023 | 3 + company1 | 07-02-2023 | 200 | | | + company1 | 07-03-2023 | 150 | | | + company1 | 07-04-2023 | 140 | 07-04-2023 | 07-06-2023 | 3 + company1 | 07-05-2023 | 150 | | | + company1 | 07-06-2023 | 90 | | | + company1 | 07-07-2023 | 110 | 07-07-2023 | 07-09-2023 | 3 + company1 | 07-08-2023 | 130 | | | + company1 | 07-09-2023 | 120 | | | + company1 | 07-10-2023 | 130 | | | 0 + company2 | 07-01-2023 | 50 | 07-01-2023 | 07-03-2023 | 3 + company2 | 07-02-2023 | 2000 | | | + company2 | 07-03-2023 | 1500 | | | + company2 | 07-04-2023 | 1400 | 07-04-2023 | 07-06-2023 | 3 + company2 | 07-05-2023 | 1500 | | | + company2 | 07-06-2023 | 60 | | | + company2 | 07-07-2023 | 1100 | 07-07-2023 | 07-09-2023 | 3 + company2 | 07-08-2023 | 1300 | | | + company2 | 07-09-2023 | 1200 | | | + company2 | 07-10-2023 | 1300 | | | 0 +(20 rows) + +-- +-- Aggregates +-- +-- using AFTER MATCH SKIP PAST LAST ROW +SELECT company, tdate, price, + first_value(price) OVER w, + last_value(price) OVER w, + max(price) OVER w, + min(price) OVER w, + sum(price) OVER w, + avg(price) OVER w, + count(price) OVER w +FROM stock +WINDOW w AS ( +PARTITION BY company +ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING +AFTER MATCH SKIP PAST LAST ROW +INITIAL +PATTERN (START UP+ DOWN+) +DEFINE +START AS TRUE, +UP AS price > PREV(price), +DOWN AS price < PREV(price) +); + company | tdate | price | first_value | last_value | max | min | sum | avg | count +----------+------------+-------+-------------+------------+------+-----+------+-----------------------+------- + company1 | 07-01-2023 | 100 | 100 | 140 | 200 | 100 | 590 | 147.5000000000000000 | 4 + company1 | 07-02-2023 | 200 | | | | | | | + company1 | 07-03-2023 | 150 | | | | | | | + company1 | 07-04-2023 | 140 | | | | | | | + company1 | 07-05-2023 | 150 | | | | | | | 0 + company1 | 07-06-2023 | 90 | 90 | 120 | 130 | 90 | 450 | 112.5000000000000000 | 4 + company1 | 07-07-2023 | 110 | | | | | | | + company1 | 07-08-2023 | 130 | | | | | | | + company1 | 07-09-2023 | 120 | | | | | | | + company1 | 07-10-2023 | 130 | | | | | | | 0 + company2 | 07-01-2023 | 50 | 50 | 1400 | 2000 | 50 | 4950 | 1237.5000000000000000 | 4 + company2 | 07-02-2023 | 2000 | | | | | | | + company2 | 07-03-2023 | 1500 | | | | | | | + company2 | 07-04-2023 | 1400 | | | | | | | + company2 | 07-05-2023 | 1500 | | | | | | | 0 + company2 | 07-06-2023 | 60 | 60 | 1200 | 1300 | 60 | 3660 | 915.0000000000000000 | 4 + company2 | 07-07-2023 | 1100 | | | | | | | + company2 | 07-08-2023 | 1300 | | | | | | | + company2 | 07-09-2023 | 1200 | | | | | | | + company2 | 07-10-2023 | 1300 | | | | | | | 0 +(20 rows) + +-- using AFTER MATCH SKIP TO NEXT ROW +SELECT company, tdate, price, + first_value(price) OVER w, + last_value(price) OVER w, + max(price) OVER w, + min(price) OVER w, + sum(price) OVER w, + avg(price) OVER w, + count(price) OVER w +FROM stock +WINDOW w AS ( +PARTITION BY company +ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING +AFTER MATCH SKIP TO NEXT ROW +INITIAL +PATTERN (START UP+ DOWN+) +DEFINE +START AS TRUE, +UP AS price > PREV(price), +DOWN AS price < PREV(price) +); + company | tdate | price | first_value | last_value | max | min | sum | avg | count +----------+------------+-------+-------------+------------+------+------+------+-----------------------+------- + company1 | 07-01-2023 | 100 | 100 | 140 | 200 | 100 | 590 | 147.5000000000000000 | 4 + company1 | 07-02-2023 | 200 | | | | | | | 0 + company1 | 07-03-2023 | 150 | | | | | | | 0 + company1 | 07-04-2023 | 140 | 140 | 90 | 150 | 90 | 380 | 126.6666666666666667 | 3 + company1 | 07-05-2023 | 150 | | | | | | | 0 + company1 | 07-06-2023 | 90 | 90 | 120 | 130 | 90 | 450 | 112.5000000000000000 | 4 + company1 | 07-07-2023 | 110 | 110 | 120 | 130 | 110 | 360 | 120.0000000000000000 | 3 + company1 | 07-08-2023 | 130 | | | | | | | 0 + company1 | 07-09-2023 | 120 | | | | | | | 0 + company1 | 07-10-2023 | 130 | | | | | | | 0 + company2 | 07-01-2023 | 50 | 50 | 1400 | 2000 | 50 | 4950 | 1237.5000000000000000 | 4 + company2 | 07-02-2023 | 2000 | | | | | | | 0 + company2 | 07-03-2023 | 1500 | | | | | | | 0 + company2 | 07-04-2023 | 1400 | 1400 | 60 | 1500 | 60 | 2960 | 986.6666666666666667 | 3 + company2 | 07-05-2023 | 1500 | | | | | | | 0 + company2 | 07-06-2023 | 60 | 60 | 1200 | 1300 | 60 | 3660 | 915.0000000000000000 | 4 + company2 | 07-07-2023 | 1100 | 1100 | 1200 | 1300 | 1100 | 3600 | 1200.0000000000000000 | 3 + company2 | 07-08-2023 | 1300 | | | | | | | 0 + company2 | 07-09-2023 | 1200 | | | | | | | 0 + company2 | 07-10-2023 | 1300 | | | | | | | 0 +(20 rows) + +-- JOIN case +CREATE TEMP TABLE t1 (i int, v1 int); +CREATE TEMP TABLE t2 (j int, v2 int); +INSERT INTO t1 VALUES(1,10); +INSERT INTO t1 VALUES(1,11); +INSERT INTO t1 VALUES(1,12); +INSERT INTO t2 VALUES(2,10); +INSERT INTO t2 VALUES(2,11); +INSERT INTO t2 VALUES(2,12); +SELECT * FROM t1, t2 WHERE t1.v1 <= 11 AND t2.v2 <= 11; + i | v1 | j | v2 +---+----+---+---- + 1 | 10 | 2 | 10 + 1 | 10 | 2 | 11 + 1 | 11 | 2 | 10 + 1 | 11 | 2 | 11 +(4 rows) + +SELECT *, count(*) OVER w FROM t1, t2 +WINDOW w AS ( + PARTITION BY t1.i + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (A) + DEFINE + A AS v1 <= 11 AND v2 <= 11 +); + i | v1 | j | v2 | count +---+----+---+----+------- + 1 | 10 | 2 | 10 | 1 + 1 | 10 | 2 | 11 | 1 + 1 | 10 | 2 | 12 | 0 + 1 | 11 | 2 | 10 | 1 + 1 | 11 | 2 | 11 | 1 + 1 | 11 | 2 | 12 | 0 + 1 | 12 | 2 | 10 | 0 + 1 | 12 | 2 | 11 | 0 + 1 | 12 | 2 | 12 | 0 +(9 rows) + +-- WITH case +WITH wstock AS ( + SELECT * FROM stock WHERE tdate < '2023-07-08' +) +SELECT tdate, price, +first_value(tdate) OVER w, +count(*) OVER w + FROM wstock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP+ DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + tdate | price | first_value | count +------------+-------+-------------+------- + 07-01-2023 | 100 | 07-01-2023 | 4 + 07-02-2023 | 200 | | + 07-03-2023 | 150 | | + 07-04-2023 | 140 | | + 07-05-2023 | 150 | | 0 + 07-06-2023 | 90 | | 0 + 07-07-2023 | 110 | | 0 + 07-01-2023 | 50 | 07-01-2023 | 4 + 07-02-2023 | 2000 | | + 07-03-2023 | 1500 | | + 07-04-2023 | 1400 | | + 07-05-2023 | 1500 | | 0 + 07-06-2023 | 60 | | 0 + 07-07-2023 | 1100 | | 0 +(14 rows) + +-- +-- Error cases +-- +-- row pattern definition variable name must not appear more than once +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + ORDER BY tdate + INITIAL + PATTERN (START UP+ DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price), + UP AS price > PREV(price) +); +ERROR: syntax error at or near "ORDER" +LINE 6: ORDER BY tdate + ^ +-- pattern variable name must appear in DEFINE +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP+ DOWN+ END) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); +ERROR: syntax error at or near "END" +LINE 8: PATTERN (START UP+ DOWN+ END) + ^ +-- FRAME must start at current row when row patttern recognition is used +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP+ DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); +ERROR: FRAME must start at current row when row patttern recognition is used +-- SEEK is not supported +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + AFTER MATCH SKIP TO NEXT ROW + SEEK + PATTERN (START UP+ DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); +ERROR: SEEK is not supported +LINE 8: SEEK + ^ +HINT: Use INITIAL. diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index f0987ff537..a6542f3dea 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -98,7 +98,7 @@ test: publication subscription # Another group of parallel tests # select_views depends on create_view # ---------- -test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps advisory_lock indirect_toast equivclass +test: select_views portals_p2 foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data window xmlmap functional_deps advisory_lock indirect_toast equivclass rpr # ---------- # Another group of parallel tests (JSON related) diff --git a/src/test/regress/sql/rpr.sql b/src/test/regress/sql/rpr.sql new file mode 100644 index 0000000000..0a69cc0e11 --- /dev/null +++ b/src/test/regress/sql/rpr.sql @@ -0,0 +1,392 @@ +-- +-- Test for row pattern definition clause +-- + +CREATE TEMP TABLE stock ( + company TEXT, + tdate DATE, + price INTEGER +); +INSERT INTO stock VALUES ('company1', '2023-07-01', 100); +INSERT INTO stock VALUES ('company1', '2023-07-02', 200); +INSERT INTO stock VALUES ('company1', '2023-07-03', 150); +INSERT INTO stock VALUES ('company1', '2023-07-04', 140); +INSERT INTO stock VALUES ('company1', '2023-07-05', 150); +INSERT INTO stock VALUES ('company1', '2023-07-06', 90); +INSERT INTO stock VALUES ('company1', '2023-07-07', 110); +INSERT INTO stock VALUES ('company1', '2023-07-08', 130); +INSERT INTO stock VALUES ('company1', '2023-07-09', 120); +INSERT INTO stock VALUES ('company1', '2023-07-10', 130); +INSERT INTO stock VALUES ('company2', '2023-07-01', 50); +INSERT INTO stock VALUES ('company2', '2023-07-02', 2000); +INSERT INTO stock VALUES ('company2', '2023-07-03', 1500); +INSERT INTO stock VALUES ('company2', '2023-07-04', 1400); +INSERT INTO stock VALUES ('company2', '2023-07-05', 1500); +INSERT INTO stock VALUES ('company2', '2023-07-06', 60); +INSERT INTO stock VALUES ('company2', '2023-07-07', 1100); +INSERT INTO stock VALUES ('company2', '2023-07-08', 1300); +INSERT INTO stock VALUES ('company2', '2023-07-09', 1200); +INSERT INTO stock VALUES ('company2', '2023-07-10', 1300); + +SELECT * FROM stock; + +-- basic test using PREV +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w, + nth_value(tdate, 2) OVER w AS nth_second + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP+ DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + +-- basic test using PREV. UP appears twice +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w, + nth_value(tdate, 2) OVER w AS nth_second + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP+ DOWN+ UP+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + +-- basic test using PREV. Use '*' +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w, + nth_value(tdate, 2) OVER w AS nth_second + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP* DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + +-- basic test with none greedy pattern +SELECT company, tdate, price, count(*) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (A A A) + DEFINE + A AS price >= 140 AND price <= 150 +); + +-- last_value() should remain consistent +SELECT company, tdate, price, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP+ DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + +-- omit "START" in DEFINE but it is ok because "START AS TRUE" is +-- implicitly defined. per spec. +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w, + nth_value(tdate, 2) OVER w AS nth_second + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP+ DOWN+) + DEFINE + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + +-- the first row start with less than or equal to 100 +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (LOWPRICE UP+ DOWN+) + DEFINE + LOWPRICE AS price <= 100, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + +-- second row raises 120% +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (LOWPRICE UP+ DOWN+) + DEFINE + LOWPRICE AS price <= 100, + UP AS price > PREV(price) * 1.2, + DOWN AS price < PREV(price) +); + +-- using NEXT +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UPDOWN) + DEFINE + START AS TRUE, + UPDOWN AS price > PREV(price) AND price > NEXT(price) +); + +-- using AFTER MATCH SKIP TO NEXT ROW +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + AFTER MATCH SKIP TO NEXT ROW + INITIAL + PATTERN (START UPDOWN) + DEFINE + START AS TRUE, + UPDOWN AS price > PREV(price) AND price > NEXT(price) +); + +-- match everything + +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + AFTER MATCH SKIP PAST LAST ROW + INITIAL + PATTERN (A+) + DEFINE + A AS TRUE +); + +-- backtracking with reclassification of rows +-- using AFTER MATCH SKIP PAST LAST ROW +SELECT company, tdate, price, first_value(tdate) OVER w, last_value(tdate) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + AFTER MATCH SKIP PAST LAST ROW + INITIAL + PATTERN (A+ B+) + DEFINE + A AS price > 100, + B AS price > 100 +); + +-- backtracking with reclassification of rows +-- using AFTER MATCH SKIP TO NEXT ROW +SELECT company, tdate, price, first_value(tdate) OVER w, last_value(tdate) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + AFTER MATCH SKIP TO NEXT ROW + INITIAL + PATTERN (A+ B+) + DEFINE + A AS price > 100, + B AS price > 100 +); + +-- ROWS BETWEEN CURRENT ROW AND offset FOLLOWING +SELECT company, tdate, price, first_value(tdate) OVER w, last_value(tdate) OVER w, + count(*) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND 2 FOLLOWING + AFTER MATCH SKIP PAST LAST ROW + PATTERN (START UP+ DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + +-- +-- Aggregates +-- + +-- using AFTER MATCH SKIP PAST LAST ROW +SELECT company, tdate, price, + first_value(price) OVER w, + last_value(price) OVER w, + max(price) OVER w, + min(price) OVER w, + sum(price) OVER w, + avg(price) OVER w, + count(price) OVER w +FROM stock +WINDOW w AS ( +PARTITION BY company +ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING +AFTER MATCH SKIP PAST LAST ROW +INITIAL +PATTERN (START UP+ DOWN+) +DEFINE +START AS TRUE, +UP AS price > PREV(price), +DOWN AS price < PREV(price) +); + +-- using AFTER MATCH SKIP TO NEXT ROW +SELECT company, tdate, price, + first_value(price) OVER w, + last_value(price) OVER w, + max(price) OVER w, + min(price) OVER w, + sum(price) OVER w, + avg(price) OVER w, + count(price) OVER w +FROM stock +WINDOW w AS ( +PARTITION BY company +ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING +AFTER MATCH SKIP TO NEXT ROW +INITIAL +PATTERN (START UP+ DOWN+) +DEFINE +START AS TRUE, +UP AS price > PREV(price), +DOWN AS price < PREV(price) +); + +-- JOIN case +CREATE TEMP TABLE t1 (i int, v1 int); +CREATE TEMP TABLE t2 (j int, v2 int); +INSERT INTO t1 VALUES(1,10); +INSERT INTO t1 VALUES(1,11); +INSERT INTO t1 VALUES(1,12); +INSERT INTO t2 VALUES(2,10); +INSERT INTO t2 VALUES(2,11); +INSERT INTO t2 VALUES(2,12); + +SELECT * FROM t1, t2 WHERE t1.v1 <= 11 AND t2.v2 <= 11; + +SELECT *, count(*) OVER w FROM t1, t2 +WINDOW w AS ( + PARTITION BY t1.i + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (A) + DEFINE + A AS v1 <= 11 AND v2 <= 11 +); + +-- WITH case +WITH wstock AS ( + SELECT * FROM stock WHERE tdate < '2023-07-08' +) +SELECT tdate, price, +first_value(tdate) OVER w, +count(*) OVER w + FROM wstock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP+ DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + +-- +-- Error cases +-- + +-- row pattern definition variable name must not appear more than once +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + ORDER BY tdate + INITIAL + PATTERN (START UP+ DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price), + UP AS price > PREV(price) +); + +-- pattern variable name must appear in DEFINE +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP+ DOWN+ END) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + +-- FRAME must start at current row when row patttern recognition is used +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING + INITIAL + PATTERN (START UP+ DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); + +-- SEEK is not supported +SELECT company, tdate, price, first_value(price) OVER w, last_value(price) OVER w + FROM stock + WINDOW w AS ( + PARTITION BY company + ORDER BY tdate + ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING + AFTER MATCH SKIP TO NEXT ROW + SEEK + PATTERN (START UP+ DOWN+) + DEFINE + START AS TRUE, + UP AS price > PREV(price), + DOWN AS price < PREV(price) +); -- 2.25.1 ----Next_Part(Mon_Jan_22_19_26_18_2024_011)-- Content-Type: Text/X-Patch; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="v13-0008-Allow-to-print-raw-parse-tree.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v1 3/4] Add alias to be used as "unset" state. @ 2025-08-30 19:34 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-08-30 19:34 UTC (permalink / raw) Add `unset_alias` string parameter to trenary reloption definition. This will allow user explicitly switch trenary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as trenary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 24662d277c8..a96abcb056c 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_trenary trenaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TRENARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TRENARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TRENARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_trenary * init_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption; newoption = (relopt_trenary *) allocate_reloption(kinds, RELOPT_TYPE_TRENARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_trenary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_trenary_reloption(bits32 kinds, const char *name, const char *desc, - trenary default_val, LOCKMODE lockmode) + trenary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_trenary *newoption = init_trenary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_trenary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, trenary default_val, - int offset) + const char* unset_alias, int offset) { relopt_trenary *newoption = init_trenary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TRENARY: { bool b; + relopt_trenary *opt = (relopt_trenary *) option->gen; + parsed = parse_bool(value, &b); option->values.trenary_val = b ? TRENARY_TRUE : TRENARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.trenary_val = TRENARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TRENARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f1..bff76dd859e 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TRENARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TRENARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7b96c7f9a80..779a6078ccb 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + trenary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TRENARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TRENARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TRENARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TRENARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cdb..527c19b6fdf 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + trenary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index 1a6717ed213..5c8eb9e97f9 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_trenary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_trenary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, trenary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_trenary_reloption(local_relopts *relopts, const char *name, const char *desc, - trenary default_val, int offset); + trenary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 08f93bde007..1a1e818bd93 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + trenary vacuum_index_cleanup; /* controls index vacuuming */ trenary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6e..e7482c0faab 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for trenary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart6784952.tM3a2QDmDi Content-Disposition: attachment; filename="v1-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v1-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2a 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..552c89869f 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treated as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart4155600.3ZeAukHxDK Content-Disposition: attachment; filename="v2a-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2a-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
* [PATCH v2 3/4] Add alias to be used as "unset" state. @ 2025-09-04 16:22 Nikolay Shaplov <[email protected]> 0 siblings, 0 replies; 813+ messages in thread From: Nikolay Shaplov @ 2025-09-04 16:22 UTC (permalink / raw) Add `unset_alias` string parameter to ternary reloption definition. This will allow user explicitly switch ternary option to "unset" state. Use this feature to implement `vacuum_index_cleanup` and gist's `buffering` reloptions as ternary reloptions --- src/backend/access/common/reloptions.c | 91 +++++++++++--------------- src/backend/access/gist/gistbuild.c | 4 +- src/backend/commands/vacuum.c | 11 ++-- src/include/access/gist_private.h | 10 +-- src/include/access/reloptions.h | 7 +- src/include/utils/rel.h | 10 +-- src/test/regress/expected/gist.out | 3 +- 7 files changed, 54 insertions(+), 82 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index f543f11001..3637646641 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -170,6 +170,27 @@ static relopt_ternary ternaryRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, + NULL, + TERNARY_UNSET + }, + { + { + "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + "auto", + TERNARY_UNSET + }, + { + { + "buffering", + "Enables buffering build for this GiST index", + RELOPT_KIND_GIST, + AccessExclusiveLock + }, + "auto", TERNARY_UNSET }, /* list terminator */ @@ -489,30 +510,6 @@ static relopt_real realRelOpts[] = {{NULL}} }; -/* values from StdRdOptIndexCleanup */ -static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = -{ - {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, - {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"off", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"true", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"false", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"yes", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"no", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {"1", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, - {"0", STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF}, - {(const char *) NULL} /* list terminator */ -}; - -/* values from GistOptBufferingMode */ -static relopt_enum_elt_def gistBufferingOptValues[] = -{ - {"auto", GIST_OPTION_BUFFERING_AUTO}, - {"on", GIST_OPTION_BUFFERING_ON}, - {"off", GIST_OPTION_BUFFERING_OFF}, - {(const char *) NULL} /* list terminator */ -}; - /* values from ViewOptCheckOption */ static relopt_enum_elt_def viewCheckOptValues[] = { @@ -524,28 +521,6 @@ static relopt_enum_elt_def viewCheckOptValues[] = static relopt_enum enumRelOpts[] = { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, { { "check_option", @@ -913,13 +888,14 @@ add_local_bool_reloption(local_relopts *relopts, const char *name, */ static relopt_ternary * init_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption; newoption = (relopt_ternary *) allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); newoption->default_val = default_val; + newoption->unset_alias = unset_alias; return newoption; } @@ -930,10 +906,10 @@ init_ternary_reloption(bits32 kinds, const char *name, const char *desc, */ void add_ternary_reloption(bits32 kinds, const char *name, const char *desc, - ternary default_val, LOCKMODE lockmode) + ternary default_val, const char* unset_alias, LOCKMODE lockmode) { relopt_ternary *newoption = init_ternary_reloption(kinds, name, desc, - default_val, lockmode); + default_val, unset_alias, lockmode); add_reloption((relopt_gen *) newoption); } @@ -947,11 +923,11 @@ add_ternary_reloption(bits32 kinds, const char *name, const char *desc, void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, ternary default_val, - int offset) + const char* unset_alias, int offset) { relopt_ternary *newoption = init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, - default_val, 0); + default_val, unset_alias, 0); add_local_reloption(relopts, (relopt_gen *) newoption, offset); } @@ -1692,8 +1668,19 @@ parse_one_reloption(relopt_value *option, char *text_str, int text_len, case RELOPT_TYPE_TERNARY: { bool b; + relopt_ternary *opt = (relopt_ternary *) option->gen; + parsed = parse_bool(value, &b); option->values.ternary_val = b ? TERNARY_TRUE : TERNARY_FALSE; + + if (!parsed && opt->unset_alias) + { + if (pg_strcasecmp(value, opt->unset_alias) == 0) + { + option->values.ternary_val = TERNARY_UNSET; + parsed = true; + } + } if (validate && !parsed) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), @@ -1988,7 +1975,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) offsetof(StdRdOptions, user_catalog_table)}, {"parallel_workers", RELOPT_TYPE_INT, offsetof(StdRdOptions, parallel_workers)}, - {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + {"vacuum_index_cleanup", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_TERNARY, offsetof(StdRdOptions, vacuum_truncate)}, diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c index 9b2ec9815f..7f641f7825 100644 --- a/src/backend/access/gist/gistbuild.c +++ b/src/backend/access/gist/gistbuild.c @@ -213,9 +213,9 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo) */ if (options) { - if (options->buffering_mode == GIST_OPTION_BUFFERING_ON) + if (options->buffering_mode == TERNARY_TRUE) buildstate.buildMode = GIST_BUFFERING_STATS; - else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF) + else if (options->buffering_mode == TERNARY_FALSE) buildstate.buildMode = GIST_BUFFERING_DISABLED; else /* must be "auto" */ buildstate.buildMode = GIST_BUFFERING_AUTO; diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 977babff54..61b4bdb682 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2175,22 +2175,21 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, */ if (params.index_cleanup == VACOPTVALUE_UNSPECIFIED) { - StdRdOptIndexCleanup vacuum_index_cleanup; + ternary vacuum_index_cleanup; if (rel->rd_options == NULL) - vacuum_index_cleanup = STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO; + vacuum_index_cleanup = TERNARY_UNSET; else vacuum_index_cleanup = ((StdRdOptions *) rel->rd_options)->vacuum_index_cleanup; - if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO) + if (vacuum_index_cleanup == TERNARY_UNSET) params.index_cleanup = VACOPTVALUE_AUTO; - else if (vacuum_index_cleanup == STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON) + else if (vacuum_index_cleanup == TERNARY_TRUE) params.index_cleanup = VACOPTVALUE_ENABLED; else { - Assert(vacuum_index_cleanup == - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF); + Assert(vacuum_index_cleanup == TERNARY_FALSE); params.index_cleanup = VACOPTVALUE_DISABLED; } } diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 39404ec7cd..a931c988fb 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -380,14 +380,6 @@ typedef struct GISTBuildBuffers int rootlevel; } GISTBuildBuffers; -/* GiSTOptions->buffering_mode values */ -typedef enum GistOptBufferingMode -{ - GIST_OPTION_BUFFERING_AUTO, - GIST_OPTION_BUFFERING_ON, - GIST_OPTION_BUFFERING_OFF, -} GistOptBufferingMode; - /* * Storage type for GiST's reloptions */ @@ -395,7 +387,7 @@ typedef struct GiSTOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ - GistOptBufferingMode buffering_mode; /* buffering build mode */ + ternary buffering_mode; /* buffering build mode */ } GiSTOptions; /* gist.c */ diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h index a436697658..d2a1c7afb7 100644 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@ -99,6 +99,7 @@ typedef struct relopt_bool typedef struct relopt_rernary { relopt_gen gen; + const char *unset_alias; /* word that will be treaed as unset value */ int default_val; } relopt_ternary; @@ -191,7 +192,8 @@ extern relopt_kind add_reloption_kind(void); extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, bool default_val, LOCKMODE lockmode); extern void add_ternary_reloption(bits32 kinds, const char *name, - const char *desc, int default_val, LOCKMODE lockmode); + const char *desc, ternary default_val, + const char* unset_alias, LOCKMODE lockmode); extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, int min_val, int max_val, LOCKMODE lockmode); @@ -213,7 +215,8 @@ extern void add_local_bool_reloption(local_relopts *relopts, const char *name, int offset); extern void add_local_ternary_reloption(local_relopts *relopts, const char *name, const char *desc, - ternary default_val, int offset); + ternary default_val, const char* unset_alias, + int offset); extern void add_local_int_reloption(local_relopts *relopts, const char *name, const char *desc, int default_val, int min_val, int max_val, int offset); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 7346d618f9..95a18c6d16 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -329,14 +329,6 @@ typedef struct AutoVacOpts float8 analyze_scale_factor; } AutoVacOpts; -/* StdRdOptions->vacuum_index_cleanup values */ -typedef enum StdRdOptIndexCleanup -{ - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO = 0, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_OFF, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON, -} StdRdOptIndexCleanup; - typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ @@ -345,7 +337,7 @@ typedef struct StdRdOptions AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ - StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ + ternary vacuum_index_cleanup; /* controls index vacuuming */ ternary vacuum_truncate; /* enables vacuum to truncate a relation */ /* diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index c75bbb23b6..76751d1859 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -12,8 +12,7 @@ create index gist_pointidx4 on gist_point_tbl using gist(p) with (buffering = au drop index gist_pointidx2, gist_pointidx3, gist_pointidx4; -- Make sure bad values are refused create index gist_pointidx5 on gist_point_tbl using gist(p) with (buffering = invalid_value); -ERROR: invalid value for enum option "buffering": invalid_value -DETAIL: Valid values are "on", "off", and "auto". +ERROR: invalid value for ternary option "buffering": invalid_value create index gist_pointidx5 on gist_point_tbl using gist(p) with (fillfactor=9); ERROR: value 9 out of bounds for option "fillfactor" DETAIL: Valid values are between "10" and "100". -- 2.39.2 --nextPart5129932.5fSG56mABF Content-Disposition: attachment; filename="v2-0004-Extra-tests.patch" Content-Transfer-Encoding: 7Bit Content-Type: text/x-patch; charset="unicode-2-0-utf-8"; name="v2-0004-Extra-tests.patch" ^ permalink raw reply [nested|flat] 813+ messages in thread
end of thread, other threads:[~2025-09-04 16:22 UTC | newest] Thread overview: 813+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2024-01-22 09:45 [PATCH v13 7/8] Row pattern recognition patch (tests). Tatsuo Ishii <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-08-30 19:34 [PATCH v1 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2a 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]> 2025-09-04 16:22 [PATCH v2 3/4] Add alias to be used as "unset" state. Nikolay Shaplov <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox